//------------------------------------------------------------------------------
// The contents of this file are subject to the nopCommerce Public License Version 1.0 ("License"); you may not use this file except in compliance with the License.
// You may obtain a copy of the License at  http://www.nopCommerce.com/License.aspx. 
// 
// Software distributed under the License is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. 
// See the License for the specific language governing rights and limitations under the License.
// 
// The Original Code is nopCommerce.
// The Initial Developer of the Original Code is NopSolutions.
// All Rights Reserved.
// 
// Contributor(s): _______. 
//------------------------------------------------------------------------------

using System;
using System.Collections.Generic;
using System.Linq;
using NopSolutions.NopCommerce.BusinessLogic.Caching;
using NopSolutions.NopCommerce.BusinessLogic.Configuration.Settings;
using NopSolutions.NopCommerce.BusinessLogic.Data;
using NopSolutions.NopCommerce.BusinessLogic.Infrastructure;
using NopSolutions.NopCommerce.Common.Utils;

namespace NopSolutions.NopCommerce.BusinessLogic.Regions
{
    /// <summary>
    /// Region service
    /// </summary>
    public partial class RegionService : IRegionService
    {
        #region Constants
        private const string RegionS_ALL_KEY = "Nop.region.all-{0}";
        private const string RegionS_BY_ID_KEY = "Nop.region.id-{0}";
        private const string PRODUCTRegionS_ALLBYRegionID_KEY = "Nop.productRegion.allbyRegionid-{0}-{1}";
        private const string PRODUCTRegionS_ALLBYPRODUCTID_KEY = "Nop.productRegion.allbyproductid-{0}-{1}";
        private const string PRODUCTRegionS_BY_ID_KEY = "Nop.productRegion.id-{0}";
        private const string RegionS_PATTERN_KEY = "Nop.Region.";
        private const string PRODUCTRegionS_PATTERN_KEY = "Nop.productRegion.";
        #endregion

        #region Fields

        /// <summary>
        /// Object context
        /// </summary>
        private readonly NopObjectContext _context;

        /// <summary>
        /// Cache manager
        /// </summary>
        private readonly ICacheManager _cacheManager;

        #endregion

        #region Ctor

        /// <summary>
        /// Ctor
        /// </summary>
        /// <param name="context">Object context</param>
        public RegionService(NopObjectContext context)
        {
            this._context = context;
            this._cacheManager = new NopRequestCache();
        }

        #endregion

        #region Methods

        /// <summary>
        /// Marks a Region as deleted
        /// </summary>
        /// <param name="RegionId">Region identifer</param>
        public void MarkRegionAsDeleted(int RegionId)
        {
            var Region = GetRegionById(RegionId);
            if (Region != null)
            {
                Region.Deleted = true;
                UpdateRegion(Region);
            }
        }

        /// <summary>
        /// Gets all Regions
        /// </summary>
        /// <returns>Region collection</returns>
        public List<Region> GetAllRegions()
        {
            bool showHidden = NopContext.Current.IsAdmin;
            return GetAllRegions(showHidden);
        }

        /// <summary>
        /// Gets all Regions
        /// </summary>
        /// <param name="showHidden">A value indicating whether to show hidden records</param>
        /// <returns>Region collection</returns>
        public List<Region> GetAllRegions(bool showHidden)
        {
            string key = string.Format(RegionS_ALL_KEY, showHidden);
            object obj2 = _cacheManager.Get(key);
            if (this.RegionsCacheEnabled && (obj2 != null))
            {
                return (List<Region>)obj2;
            }

            
            var query = from m in _context.Regions
                        orderby m.DisplayOrder
                        where (showHidden || m.Published) &&
                        !m.Deleted
                        select m;
            var Regions = query.ToList();

            if (this.RegionsCacheEnabled)
            {
                _cacheManager.Add(key, Regions);
            }
            return Regions;
        }

        /// <summary>
        /// Gets a Region
        /// </summary>
        /// <param name="RegionId">Region identifier</param>
        /// <returns>Region</returns>
        public Region GetRegionById(int RegionId)
        {
            if (RegionId == 0)
                return null;

            string key = string.Format(RegionS_BY_ID_KEY, RegionId);
            object obj2 = _cacheManager.Get(key);
            if (this.RegionsCacheEnabled && (obj2 != null))
            {
                return (Region)obj2;
            }

            
            var query = from m in _context.Regions
                        where m.RegionID == RegionId
                        select m;
            var Region = query.SingleOrDefault();

            if (this.RegionsCacheEnabled)
            {
                _cacheManager.Add(key, Region);
            }
            return Region;
        }

        /// <summary>
        /// Inserts a Region
        /// </summary>
        /// <param name="Region">Region</param>
        public void InsertRegion(Region Region)
        {
            if (Region == null)
                throw new ArgumentNullException("Region");
            
            Region.Name = CommonHelper.EnsureNotNull(Region.Name);
            Region.Name = CommonHelper.EnsureMaximumLength(Region.Name, 400);
            Region.Description = CommonHelper.EnsureNotNull(Region.Description);
            Region.MetaKeywords = CommonHelper.EnsureNotNull(Region.MetaKeywords);
            Region.MetaKeywords = CommonHelper.EnsureMaximumLength(Region.MetaKeywords, 400);
            Region.MetaDescription = CommonHelper.EnsureNotNull(Region.MetaDescription);
            Region.MetaDescription = CommonHelper.EnsureMaximumLength(Region.MetaDescription, 4000);
            Region.MetaTitle = CommonHelper.EnsureNotNull(Region.MetaTitle);
            Region.MetaTitle = CommonHelper.EnsureMaximumLength(Region.MetaTitle, 400);
            Region.SEName = CommonHelper.EnsureNotNull(Region.SEName);
            Region.SEName = CommonHelper.EnsureMaximumLength(Region.SEName, 100);
            Region.PriceRanges = CommonHelper.EnsureNotNull(Region.PriceRanges);
            Region.PriceRanges = CommonHelper.EnsureMaximumLength(Region.PriceRanges, 400);

            
            
            _context.Regions.AddObject(Region);
            _context.SaveChanges();

            if (this.RegionsCacheEnabled || this.MappingsCacheEnabled)
            {
                _cacheManager.RemoveByPattern(RegionS_PATTERN_KEY);
                _cacheManager.RemoveByPattern(PRODUCTRegionS_PATTERN_KEY);
            }
        }

        /// <summary>
        /// Updates the Region
        /// </summary>
        /// <param name="Region">Region</param>
        public void UpdateRegion(Region Region)
        {
            if (Region == null)
                throw new ArgumentNullException("Region");

            Region.Name = CommonHelper.EnsureNotNull(Region.Name);
            Region.Name = CommonHelper.EnsureMaximumLength(Region.Name, 400);
            Region.Description = CommonHelper.EnsureNotNull(Region.Description);
            Region.MetaKeywords = CommonHelper.EnsureNotNull(Region.MetaKeywords);
            Region.MetaKeywords = CommonHelper.EnsureMaximumLength(Region.MetaKeywords, 400);
            Region.MetaDescription = CommonHelper.EnsureNotNull(Region.MetaDescription);
            Region.MetaDescription = CommonHelper.EnsureMaximumLength(Region.MetaDescription, 4000);
            Region.MetaTitle = CommonHelper.EnsureNotNull(Region.MetaTitle);
            Region.MetaTitle = CommonHelper.EnsureMaximumLength(Region.MetaTitle, 400);
            Region.SEName = CommonHelper.EnsureNotNull(Region.SEName);
            Region.SEName = CommonHelper.EnsureMaximumLength(Region.SEName, 100);
            Region.PriceRanges = CommonHelper.EnsureNotNull(Region.PriceRanges);
            Region.PriceRanges = CommonHelper.EnsureMaximumLength(Region.PriceRanges, 400);

            
            if (!_context.IsAttached(Region))
                _context.Regions.Attach(Region);

            _context.SaveChanges();

            if (this.RegionsCacheEnabled || this.MappingsCacheEnabled)
            {
                _cacheManager.RemoveByPattern(RegionS_PATTERN_KEY);
                _cacheManager.RemoveByPattern(PRODUCTRegionS_PATTERN_KEY);
            }
        }

        /// <summary>
        /// Gets localized Region by id
        /// </summary>
        /// <param name="RegionLocalizedId">Localized Region identifier</param>
        /// <returns>Region content</returns>
        public RegionLocalized GetRegionLocalizedById(int RegionLocalizedId)
        {
            if (RegionLocalizedId == 0)
                return null;

            
            var query = from ml in _context.RegionLocalizeds
                        where ml.RegionLocalizedID == RegionLocalizedId
                        select ml;
            var RegionLocalized = query.SingleOrDefault();
            return RegionLocalized;
        }

        /// <summary>
        /// Gets localized Region by Region id
        /// </summary>
        /// <param name="RegionId">Region identifier</param>
        /// <returns>Region content</returns>
        public List<RegionLocalized> GetRegionLocalizedByRegionId(int RegionId)
        {
            if (RegionId == 0)
                return new List<RegionLocalized>();

            
            var query = from ml in _context.RegionLocalizeds
                        where ml.RegionID == RegionId
                        select ml;
            var content = query.ToList();
            return content;
        }

        /// <summary>
        /// Gets localized Region by Region id and language id
        /// </summary>
        /// <param name="RegionId">Region identifier</param>
        /// <param name="languageId">Language identifier</param>
        /// <returns>Region content</returns>
        public RegionLocalized GetRegionLocalizedByRegionIdAndLanguageId(int RegionId, int languageId)
        {
            if (RegionId == 0 || languageId == 0)
                return null;

            
            var query = from ml in _context.RegionLocalizeds
                        orderby ml.RegionLocalizedID
                        where ml.RegionID == RegionId &&
                        ml.LanguageID == languageId
                        select ml;
            var RegionLocalized = query.FirstOrDefault();
            return RegionLocalized;
        }

        /// <summary>
        /// Inserts a localized Region
        /// </summary>
        /// <param name="RegionLocalized">Region content</param>
        public void InsertRegionLocalized(RegionLocalized RegionLocalized)
        {
            if (RegionLocalized == null)
                throw new ArgumentNullException("RegionLocalized");

            RegionLocalized.Name = CommonHelper.EnsureNotNull(RegionLocalized.Name);
            RegionLocalized.Name = CommonHelper.EnsureMaximumLength(RegionLocalized.Name, 400);
            RegionLocalized.Description = CommonHelper.EnsureNotNull(RegionLocalized.Description);
            RegionLocalized.MetaKeywords = CommonHelper.EnsureNotNull(RegionLocalized.MetaKeywords);
            RegionLocalized.MetaKeywords = CommonHelper.EnsureMaximumLength(RegionLocalized.MetaKeywords, 400);
            RegionLocalized.MetaDescription = CommonHelper.EnsureNotNull(RegionLocalized.MetaDescription);
            RegionLocalized.MetaDescription = CommonHelper.EnsureMaximumLength(RegionLocalized.MetaDescription, 4000);
            RegionLocalized.MetaTitle = CommonHelper.EnsureNotNull(RegionLocalized.MetaTitle);
            RegionLocalized.MetaTitle = CommonHelper.EnsureMaximumLength(RegionLocalized.MetaTitle, 400);
            RegionLocalized.SEName = CommonHelper.EnsureNotNull(RegionLocalized.SEName);
            RegionLocalized.SEName = CommonHelper.EnsureMaximumLength(RegionLocalized.SEName, 100);

            

            _context.RegionLocalizeds.AddObject(RegionLocalized);
            _context.SaveChanges();

            if (this.RegionsCacheEnabled)
            {
                _cacheManager.RemoveByPattern(RegionS_PATTERN_KEY);
            }
        }

        /// <summary>
        /// Update a localized Region
        /// </summary>
        /// <param name="RegionLocalized">Region content</param>
        public void UpdateRegionLocalized(RegionLocalized RegionLocalized)
        {
            if (RegionLocalized == null)
                throw new ArgumentNullException("RegionLocalized");

            RegionLocalized.Name = CommonHelper.EnsureNotNull(RegionLocalized.Name);
            RegionLocalized.Name = CommonHelper.EnsureMaximumLength(RegionLocalized.Name, 400);
            RegionLocalized.Description = CommonHelper.EnsureNotNull(RegionLocalized.Description);
            RegionLocalized.MetaKeywords = CommonHelper.EnsureNotNull(RegionLocalized.MetaKeywords);
            RegionLocalized.MetaKeywords = CommonHelper.EnsureMaximumLength(RegionLocalized.MetaKeywords, 400);
            RegionLocalized.MetaDescription = CommonHelper.EnsureNotNull(RegionLocalized.MetaDescription);
            RegionLocalized.MetaDescription = CommonHelper.EnsureMaximumLength(RegionLocalized.MetaDescription, 4000);
            RegionLocalized.MetaTitle = CommonHelper.EnsureNotNull(RegionLocalized.MetaTitle);
            RegionLocalized.MetaTitle = CommonHelper.EnsureMaximumLength(RegionLocalized.MetaTitle, 400);
            RegionLocalized.SEName = CommonHelper.EnsureNotNull(RegionLocalized.SEName);
            RegionLocalized.SEName = CommonHelper.EnsureMaximumLength(RegionLocalized.SEName, 100);

            bool allFieldsAreEmpty = string.IsNullOrEmpty(RegionLocalized.Name) &&
                string.IsNullOrEmpty(RegionLocalized.Description) &&
                string.IsNullOrEmpty(RegionLocalized.MetaKeywords) &&
                string.IsNullOrEmpty(RegionLocalized.MetaDescription) &&
                string.IsNullOrEmpty(RegionLocalized.MetaTitle) &&
                string.IsNullOrEmpty(RegionLocalized.SEName);

            
            if (!_context.IsAttached(RegionLocalized))
                _context.RegionLocalizeds.Attach(RegionLocalized);

            if (allFieldsAreEmpty)
            {
                //delete if all fields are empty
                _context.DeleteObject(RegionLocalized);
                _context.SaveChanges();
            }
            else
            {
                _context.SaveChanges();
            }

            if (this.RegionsCacheEnabled)
            {
                _cacheManager.RemoveByPattern(RegionS_PATTERN_KEY);
            }
        }

        /// <summary>
        /// Deletes a product Region mapping
        /// </summary>
        /// <param name="productRegionId">Product Region mapping identifer</param>
        public void DeleteProductRegion(int productRegionId)
        {
            if (productRegionId == 0)
                return;

            var productRegion = GetProductRegionById(productRegionId);
            if (productRegion == null)
                return;

            
            if (!_context.IsAttached(productRegion))
                _context.ProductRegions.Attach(productRegion);
            _context.DeleteObject(productRegion);
            _context.SaveChanges();

            if (this.RegionsCacheEnabled || this.MappingsCacheEnabled)
            {
                _cacheManager.RemoveByPattern(RegionS_PATTERN_KEY);
                _cacheManager.RemoveByPattern(PRODUCTRegionS_PATTERN_KEY);
            }
        }

        /// <summary>
        /// Gets product Region collection
        /// </summary>
        /// <param name="RegionId">Region identifier</param>
        /// <returns>Product Region collection</returns>
        public List<ProductRegion> GetProductRegionsByRegionId(int RegionId)
        {
            if (RegionId == 0)
                return new List<ProductRegion>();

            bool showHidden = NopContext.Current.IsAdmin;
            string key = string.Format(PRODUCTRegionS_ALLBYRegionID_KEY, showHidden, RegionId);
            object obj2 = _cacheManager.Get(key);
            if (this.MappingsCacheEnabled && (obj2 != null))
            {
                return (List<ProductRegion>)obj2;
            }

            
            var query = from pm in _context.ProductRegions
                        join p in _context.Products on pm.ProductID equals p.ProductId
                        where pm.RegionID == RegionId &&
                        !p.Deleted &&
                        (showHidden || p.Published)
                        orderby pm.DisplayOrder
                        select pm;
            var productRegions = query.ToList();

            if (this.MappingsCacheEnabled)
            {
                _cacheManager.Add(key, productRegions);
            }
            return productRegions;
        }

        /// <summary>
        /// Gets a product Region mapping collection
        /// </summary>
        /// <param name="productId">Product identifier</param>
        /// <returns>Product Region mapping collection</returns>
        public List<ProductRegion> GetProductRegionsByProductId(int productId)
        {
            if (productId == 0)
                return new List<ProductRegion>();

            bool showHidden = NopContext.Current.IsAdmin;
            string key = string.Format(PRODUCTRegionS_ALLBYPRODUCTID_KEY, showHidden, productId);
            object obj2 = _cacheManager.Get(key);
            if (this.MappingsCacheEnabled && (obj2 != null))
            {
                return (List<ProductRegion>)obj2;
            }

            
            var query = from pm in _context.ProductRegions
                        join m in _context.Regions on pm.RegionID equals m.RegionID
                        where pm.ProductID == productId &&
                        !m.Deleted &&
                        (showHidden || m.Published)
                        orderby pm.DisplayOrder
                        select pm;
            var productRegions = query.ToList();

            if (this.MappingsCacheEnabled)
            {
                _cacheManager.Add(key, productRegions);
            }
            return productRegions;
        }

        /// <summary>
        /// Gets a product Region mapping 
        /// </summary>
        /// <param name="productRegionId">Product Region mapping identifier</param>
        /// <returns>Product Region mapping</returns>
        public ProductRegion GetProductRegionById(int productRegionId)
        {
            if (productRegionId == 0)
                return null;

            string key = string.Format(PRODUCTRegionS_BY_ID_KEY, productRegionId);
            object obj2 = _cacheManager.Get(key);
            if (this.MappingsCacheEnabled && (obj2 != null))
            {
                return (ProductRegion)obj2;
            }

            
            var query = from pm in _context.ProductRegions
                        where pm.ProductRegionID == productRegionId
                        select pm;
            var productRegion = query.SingleOrDefault();

            if (this.MappingsCacheEnabled)
            {
                _cacheManager.Add(key, productRegion);
            }
            return productRegion;
        }

        /// <summary>
        /// Inserts a product Region mapping
        /// </summary>
        /// <param name="productRegion">Product Region mapping</param>
        public void InsertProductRegion(ProductRegion productRegion)
        {
            if (productRegion == null)
                throw new ArgumentNullException("productRegion");

            

            _context.ProductRegions.AddObject(productRegion);
            _context.SaveChanges();

            if (this.RegionsCacheEnabled || this.MappingsCacheEnabled)
            {
                _cacheManager.RemoveByPattern(RegionS_PATTERN_KEY);
                _cacheManager.RemoveByPattern(PRODUCTRegionS_PATTERN_KEY);
            }
        }

        /// <summary>
        /// Updates the product Region mapping
        /// </summary>
        /// <param name="productRegion">Product Region mapping</param>
        public void UpdateProductRegion(ProductRegion productRegion)
        {
            if (productRegion == null)
                throw new ArgumentNullException("productRegion");

            
            if (!_context.IsAttached(productRegion))
                _context.ProductRegions.Attach(productRegion);

            _context.SaveChanges();

            if (this.RegionsCacheEnabled || this.MappingsCacheEnabled)
            {
                _cacheManager.RemoveByPattern(RegionS_PATTERN_KEY);
                _cacheManager.RemoveByPattern(PRODUCTRegionS_PATTERN_KEY);
            }
        }
        #endregion

        #region Properties

        /// <summary>
        /// Gets a value indicating whether Regions cache is enabled
        /// </summary>
        public bool RegionsCacheEnabled
        {
            get
            {
                return IoC.Resolve<ISettingManager>().GetSettingValueBoolean("Cache.RegionManager.RegionsCacheEnabled");
            }
        }

        /// <summary>
        /// Gets a value indicating whether mappings cache is enabled
        /// </summary>
        public bool MappingsCacheEnabled
        {
            get
            {
                return IoC.Resolve<ISettingManager>().GetSettingValueBoolean("Cache.RegionManager.MappingsCacheEnabled");
            }
        }
        #endregion
    }
}
